package cn.snmp.mutual.common.snmp;

import lombok.extern.slf4j.Slf4j;
import org.snmp4j.smi.AbstractVariable;
import org.snmp4j.smi.Counter32;
import org.snmp4j.smi.Counter64;
import org.snmp4j.smi.Gauge32;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.IpAddress;
import org.snmp4j.smi.Null;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.Opaque;
import org.snmp4j.smi.TimeTicks;
import org.snmp4j.smi.UnsignedInteger32;
import org.snmp4j.smi.VariableBinding;

import cn.snmp.mutual.nms.SnmpAPI;
import cn.snmp.mutual.nms.SnmpCounter;
import cn.snmp.mutual.nms.SnmpCounter64;
import cn.snmp.mutual.nms.SnmpGauge;
import cn.snmp.mutual.nms.SnmpInt;
import cn.snmp.mutual.nms.SnmpIpAddress;
import cn.snmp.mutual.nms.SnmpOpaque;
import cn.snmp.mutual.nms.SnmpString;
import cn.snmp.mutual.nms.SnmpTimeticks;
import cn.snmp.mutual.nms.SnmpUnsignedInt;
import cn.snmp.mutual.nms.SnmpVar;
import cn.snmp.mutual.data.ObjService;
import cn.snmp.mutual.uk.stack.AsnObject;
import cn.snmp.mutual.uk.stack.AsnOctets;
import cn.snmp.mutual.uk.stack.SnmpConstants;
/**
 * @since 2018.9.16
 * @author dengkn
 * 数据处理工具，封装交互的snmp 信息，包括 snmpVersion，IPAddress，SNMPPort，SnmpUserName，
 * AuthProcotol，AuthPassword，PrivProcotol，PrivPassword
 * ，交互的数据格式
 */
@Slf4j
public class SnmpNioTargetUtilities {
	
	private static final String VSION_SNMP_V3 = "V3";
	private static final String VSION_SNMP_V2 = "V2";
	private static final String VSION_SNMP_V1 = "V1";
	private static final String VSION_SNMP_V3_3 = "3";
	private static final String VSION_SNMP_V1_1 = "1";
	private static final String VSION_SNMP_V2C = "V2c";
	private static final String VSION_SNMP_V2_2 = "2";
	private static final String SNMP_SECUER_FRIDE_ONE = "Auth,Priv";
	private static final String SNMP_SECUER_FRIDE_TWO = "Auth,noPriv";
	private static final String SNMP_SECUER_FRIDE_THREE = "noAuth,noPriv";

	public static SnmpNioTarget getSnmpNioTarget(ObjService snmpParam) {
		try {

			int version = SnmpNioTarget.VERSION2C;
			String ip = snmpParam.getStringValue("IPAddress");
			int port = Integer.parseInt(snmpParam.getStringValue("SNMPPort"));
			String strVersion = snmpParam.getStringValue("snmpVersion");

			if (strVersion.equalsIgnoreCase(VSION_SNMP_V3) || strVersion.equalsIgnoreCase(VSION_SNMP_V3_3)) {
				version = SnmpNioTarget.VERSION3;
			}
			if (strVersion.equalsIgnoreCase(VSION_SNMP_V2) || strVersion.equalsIgnoreCase(VSION_SNMP_V2C) || strVersion.equalsIgnoreCase(VSION_SNMP_V2_2)) {
				version = SnmpNioTarget.VERSION2C;
			} else if (strVersion.equalsIgnoreCase(VSION_SNMP_V1) || strVersion.equalsIgnoreCase(VSION_SNMP_V1_1)) {
				version = SnmpNioTarget.VERSION1;
			}

			SnmpNioTarget target = new SnmpNioTarget(snmpParam);
			target.setSnmpVersion(version);
			target.setTargetHost(ip);
			target.setTargetPort(port);

			return target;
		} catch (Exception e) {
			log.error("getSnmpNioTarget error!", e);
			return null;
		}
	}

	public static void initSnmpNioTarget(SnmpNioTarget target, ObjService snmpParam) throws Exception {
		try {
			initParam(target, snmpParam);
			String strVersion = snmpParam.getStringValue("SNMPVersion");
			if (strVersion.equalsIgnoreCase(VSION_SNMP_V3) || strVersion.equalsIgnoreCase(VSION_SNMP_V3_3)) {
				String strContextName = snmpParam.getStringValue("ContextName");
				String strContextEngineId = snmpParam.getStringValue("ContextEngineId");
				String strSnmpUserName = snmpParam.getStringValue("SnmpUserName");
				String strSecurityLevel = snmpParam.getStringValue("SecurityLevel");
				String strAuthProcotol = snmpParam.getStringValue("AuthProcotol");
				String strAuthPassword = snmpParam.getStringValue("AuthPassword");
				String strPrivProcotol = snmpParam.getStringValue("PrivProcotol");
				String strPrivPassword = snmpParam.getStringValue("PrivPassword");
				boolean bUseAuthentication = false;
				int iAuthenticationProtocol = SnmpNioTarget.MD5_PROTOCOL;
				if (strSecurityLevel.equalsIgnoreCase(SNMP_SECUER_FRIDE_ONE)) {
					bUseAuthentication = true;
					boolean bUsePrivacy = true;
					int iPrivacyProtocol = SnmpNioTarget.DES_PROTOCOL;
					if (strAuthProcotol.equalsIgnoreCase("MD5")) {
						iAuthenticationProtocol = SnmpNioTarget.MD5_PROTOCOL;
					} else if (strAuthProcotol.equalsIgnoreCase("SHA")) {
						iAuthenticationProtocol = SnmpNioTarget.SHA1_PROTOCOL;
					}
					if (strPrivProcotol.equalsIgnoreCase("DES")) {
						iPrivacyProtocol = SnmpNioTarget.DES_PROTOCOL;
					} else if (strPrivProcotol.equalsIgnoreCase("AES")) {
						iPrivacyProtocol = SnmpNioTarget.AES_PROTOCOL;
					}
					target.setV3Params(strContextName, strContextEngineId, strSnmpUserName, bUseAuthentication,
							iAuthenticationProtocol, strAuthPassword, bUsePrivacy, iPrivacyProtocol, strPrivPassword);
				} else if (strSecurityLevel.equalsIgnoreCase(SNMP_SECUER_FRIDE_TWO)) {
					bUseAuthentication = true;
					if (strAuthProcotol.equalsIgnoreCase("MD5")) {
						iAuthenticationProtocol = SnmpNioTarget.MD5_PROTOCOL;
					} else if (strAuthProcotol.equalsIgnoreCase("SHA")) {
						iAuthenticationProtocol = SnmpNioTarget.SHA1_PROTOCOL;
					}
					target.setV3Params(strContextName, strContextEngineId, strSnmpUserName, bUseAuthentication,
							iAuthenticationProtocol, strAuthPassword);
				} else if (strSecurityLevel.equalsIgnoreCase(SNMP_SECUER_FRIDE_THREE)) {

					target.setV3Params(strContextName, strContextEngineId, strSnmpUserName);
				}
			}
		} catch (Exception e) {
			log.error("init SnmpNioTarget error!It may be the information error of network element." + e);
		}
	}
	private static void initParam(SnmpNioTarget target, ObjService snmpParam) {
		String retriesStr = snmpParam.getStringValue("Retry");
		if(retriesStr == null || "".equals(retriesStr)) {
			target.setRetries(1);
		} else {
			int retries=0;
			try {
				retries = Integer.parseInt(retriesStr);
			}catch(Exception e) {
				log.error("retriesStr equals null, error!But it doesn't matter. I have modified the default value to 1." + e);
			}
			target.setRetries(retries);
		}
		target.setTimeout(getTimout(snmpParam.getStringValue("Timeout")));
	}
	
	private static int getTimout(String timout) {
		int timoutInt = 3;
		if (timout != null) {
			try {
				timoutInt = Integer.parseInt(timout);
			} catch (Exception e) {
				log.error("mutual timeout no config or error! But it doesn't matter. I have modified the default value to 3."+ e);
			}
		}
		return timoutInt;
	}
	
	/**
	 * 对接收的数据作转换 原来的changeVariable方法
	 */
	public static SnmpVar changeVariable(VariableBinding src) {
		try {
			Integer ing = new Integer(src.getSyntax());
			byte vartype = ing.byteValue();

			SnmpVar desc = null;
            //将变量值toString
			String value = src.toValueString();
			if (vartype == SnmpConstants.INTEGER) {
				desc = SnmpVar.createVariable(value, SnmpAPI.INTEGER);
			} else if (vartype == SnmpConstants.STRING) {
				AsnOctets aos = new AsnOctets(value);				
				byte[] strByteList = ((AsnOctets) aos).getBytes();
				desc = (SnmpVar) new SnmpString(strByteList);
			} else if (vartype == SnmpConstants.OBJID) {
				if (value.startsWith(".")) {
					desc = SnmpVar.createVariable(value, SnmpAPI.OBJID);
				}
				else {
					desc = SnmpVar.createVariable("." + value, SnmpAPI.OBJID);
				}
					
			} else if (vartype == SnmpConstants.NULLOBJ) {
				desc = SnmpVar.createVariable(value, SnmpAPI.NULLOBJ);
			} else if (vartype == SnmpConstants.IPADDRESS) {
				desc = SnmpVar.createVariable(value, SnmpAPI.IPADDRESS);
			} else if (vartype == SnmpConstants.ASN_BIT_STR) {
				desc = SnmpVar.createVariable(value, SnmpAPI.BITSTRING);
			} else if (vartype == SnmpConstants.COUNTER) {
				desc = SnmpVar.createVariable(value, SnmpAPI.COUNTER);
			} else if (vartype == SnmpConstants.GAUGE) {
				desc = SnmpVar.createVariable(value, SnmpAPI.GAUGE);
			}
			else if (vartype == SnmpConstants.TIMETICKS) {
				desc = SnmpVar.createVariable(""+src.getVariable().toLong(), SnmpAPI.TIMETICKS);
			} else if (vartype == SnmpConstants.OPAQUE) {
				desc = SnmpVar.createVariable(value, SnmpAPI.OPAQUE);
			} else if (vartype == SnmpConstants.NSAP_ADDRESS) {
				desc = SnmpVar.createVariable(value, SnmpAPI.NSAP);
			} else if (vartype == SnmpConstants.COUNTER64) {
				desc = SnmpVar.createVariable(value, SnmpAPI.COUNTER64);
			} else if (vartype == SnmpConstants.OBSOLETED_RFC1442_UINTEGER32) {
				desc = SnmpVar.createVariable(value, SnmpAPI.UINTEGER32);
			} else {
				desc = SnmpVar.createVariable(value, SnmpAPI.NULLOBJ);
			}
			return desc;
		} catch (Exception e) {
			log.error("changeVariable error!", e);
			return null;
		}
	}
	
	
	/**
	 * 对要下发的数据作转换
	 */
	public static AbstractVariable changeVariable(SnmpVar src) {
		try {
			byte vartype = src.getType();
			AbstractVariable desc = null;
			String value = src.toString();
			if (vartype == SnmpAPI.INTEGER) {
				desc = new Integer32(((SnmpInt) src).intValue());
			} else if (vartype == SnmpAPI.STRING) {
				byte[] strByteList = ((SnmpString) src).toBytes();
				desc = new OctetString(strByteList);
			} else if (vartype == SnmpAPI.OBJID) {
				desc = new OID(value);
			} else if (vartype == SnmpAPI.NULLOBJ) {
				desc = new Null();
			} else if (vartype == SnmpAPI.IPADDRESS) {
				desc = new IpAddress(((SnmpIpAddress) src).toBytes());
			} else if (vartype == SnmpAPI.BITSTRING) {
				byte[] strByteList = ((SnmpString) src).toBytes();
				desc = new OctetString(strByteList);
			} else if (vartype == SnmpAPI.COUNTER) {
				desc = new Counter32(((SnmpCounter) src).longValue());
			} else if (vartype == SnmpAPI.GAUGE) {
				desc = new Gauge32(((SnmpGauge) src).longValue());
			} else if (vartype == SnmpAPI.TIMETICKS) {
				desc = new TimeTicks(((SnmpTimeticks) src).longValue());
			} else if (vartype == SnmpAPI.OPAQUE) {
				desc = new Opaque(((SnmpOpaque) src).toBytes());
			} else if (vartype == SnmpAPI.NSAP) {
				desc = new IpAddress(((SnmpIpAddress) src).toBytes());
			} else if (vartype == SnmpAPI.COUNTER64) {
				desc = new Counter64(((SnmpCounter64) src).toBigInteger().longValue());
			} else if (vartype == SnmpAPI.UINTEGER32) {
				desc = new UnsignedInteger32(((SnmpUnsignedInt) src).longValue());
			} else {
				if (AsnObject.debug > 6) {
					log.info("Type String Name : [" + src.getTypeString() + "] not found...");
				}
			}
			return desc;
		} catch (Exception e) {
			log.error("SnmpNioTargetUtilities error! This is a difficult question. Let's take a look at it slowly.");
			if (AsnObject.debug > 6) {
				log.error("This is a difficult question. Let's take a look at it slowly.", e);
			}
			return null;
		}
	}
    
}
